package com.katze.boot.applet.asn1.anlysis;

import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 说  明：解析二进制话单
 * 作  者：zf.zeng
 * 日  期：2022-07-20 (星期三)
 **/
public class BinaryAnalysis extends AnalysisHelper {
    private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    private Map<String, Map<String, String>> conf;

    public BinaryAnalysis(){}

    public BinaryAnalysis config(String filename) {
        if (StringUtils.isBlank(filename)) return this;
        try {
            this.conf = super.load(filename);
        } catch (IOException e) {
            throw new RuntimeException("配置文件：" + filename + "加载失败", e);
        }
        return this;
    }

    public void storage(Path file){
        super.initDir(file);
    }

    @Override
    protected Map<String, Object> read(Object data){
        Map<String, Object> rs = new LinkedHashMap<>();
        if (conf != null && conf.size() > 0){
            getOrgValue((byte[]) data, rs);
        }
        return rs;
    }

    private void getOrgValue(byte[] values, Map<String, Object> orgMap){
        int position = 0;
        for (Map.Entry<String, Map<String, String>> field : conf.entrySet()) {
            byte[] value;
            if(values.length >= position) {
                value = new byte[Integer.parseInt(field.getValue().get("length"))];
                System.arraycopy(values, position, value,0, value.length);
                position += value.length;
            } else {
                value = new byte[0];
            }

            if("SEQUENCE_OF_SEQUENCE".equals(field.getValue().get("type"))){
//            if(value.length > 0) orgMap.put(field.get("name"), analyticListData(value, field, resources));
            } else if("SEQUENCE".equals(field.getValue().get("type"))){
//            if(value.length > 0) orgMap.put(field.get("name"), analyticMapData(value, field, resources));
            } else {
                //含拼接符则表示该字段为子字段，而子字段会在以上两种类型中解析，故此处过滤
                orgMap.put(field.getValue().get("name"), value.length == 0? "": converter(field.getValue(), value));
            }
        }
    }


    protected String converter(Map<String, String> field, byte[] bytes){
        Object value;
        switch (field.get("type").toUpperCase()){
            case "INTEGER":
                value = toInteger4(bytes);
                break;
            case "BCD":
            case "BCDF":
                value = toBCD(bytes, false);
                if("BCDF".equals(field.get("type"))){
                    value = remove(value.toString());
                }
                break;
            case "HEX":
            case "HEXF":
                value = ASN1Analysis.toShortHexString(bytes);
                if("HEXF".equals(field.get("type"))){
                    value = remove(value.toString());
                }
                break;
            case "CDMAGW_CALLNUMBER":
                int length = bytes[1] & 0xFF;
                length = Math.min(length, Integer.parseInt(field.get("length")) - 2);
                byte[] phone = new byte[length];
                System.arraycopy(bytes, 2, phone, 0, phone.length);
                value = ASN1Analysis.toShortHexString(phone).replace("F", "");
                // 综合关口局  判断是否国际号码
                if ((((bytes[0] >> 4) & 0x07) & 0xff) == 1 && !value.toString().startsWith("0")){
                    value = "00" + value;
                }
                break;
            case "TIMEYY":
                value = toDateTimeYMDHMS(bytes, 1, 1, 1, 1, 1, 1);
                break;
            case "TIMEYYYY":
                value = toDateTimeYMDHMS(bytes, 2, 1, 1, 1, 1, 1);
                break;
            case "ASCII":
                value=new String(bytes, StandardCharsets.UTF_8);
                break;
            default:
                value = ASN1Analysis.toShortHexString(bytes);
                break;
        }
        return Objects.toString(value);
    }


    /**
     * 从尾部开始移除占位符‘F’
     * @param value 数据值
     */
    protected String remove(String value){
        String[] values = value.split("");
        int index = values.length;
        for (int i = values.length - 1; i >= 0; i--) {
            index = i;
            if(!values[i].equals("F")) break;
        }
        value = value.substring(0, index+1);
        return value.toUpperCase().trim().equals("F")? "":value;//BUG:27849-分布式处理后的数据：（丢失最后一个数值）
    }

    /**
     * 占用四个字节，其中低位字节在前，高位字节在后
     * @param bytes 字节值
     */
    protected int toInteger4(byte[] bytes){
        byte[] buffer = new byte[0];
        if(bytes.length < 4){
            buffer = new byte[4];
            System.arraycopy(bytes, 0, buffer, 0, bytes.length);
        } else if (bytes.length == 4){
            buffer = bytes;
        }
//        return (buffer[0] & 0xff) | ((buffer[1] << 8) & 0xff00) | ((buffer[2] << 24) >>> 8) | (buffer[3] << 24);
        int value=0;
        if (buffer.length > 0){
            for(int i = 0; i < 4; i++) {
                value |= (buffer[i] & 0xFF) << ( i * 8);
            }
        }
        return value;
    }

    /**
     * 解低位在前
     * @param bytes 字节值
     */
    protected long toLong(byte[] bytes) {
        long  value = 0;
        for (byte aByte : bytes) {
            value <<= 8;
            value |= (aByte & 0xff);
        }
        return value;
    }

    /**
     * BCD码
     * @param data 字节值
     * @param rmf 是否保留占位符
     */
    protected String toBCD(byte[] data, boolean rmf){
        StringBuilder buffer = new StringBuilder();
        if(data != null){
            for (byte datum : data) {
                int n1 = (datum >> 4) & 0xF;
                int n2 = datum & 0xF;

                if(n1 == 15){
                    if(!rmf) buffer.append(HEX_CHAR[n1]);
                }else {
                    buffer.append(HEX_CHAR[n1]);
                }

                if(n2 == 15){
                    if(!rmf) buffer.append(HEX_CHAR[n2]);
                }else {
                    buffer.append(HEX_CHAR[n2]);
                }
            }
        }
        return buffer.toString();
    }

    /**
     * 年份的格式为Intel字节序，长度为2个字节，其中低位字节在前，高位字节在后。其余部分长度为1个字节
     * @param data 字节数组
     * @param position 时间长度
     */
    protected String toDateTimeYMDHMS(byte[] data, Integer... position){
        int index = 0;
        StringBuilder dateValue = new StringBuilder();
        for (Integer item : position) {
            byte[] bytes = new byte[item];
            System.arraycopy(data, index, bytes,0, bytes.length);
            index += item;
            long value = toInteger4(bytes);
            if(value < 10){
                dateValue.append("0").append(value);
            } else {
                dateValue.append(value);
            }
        }
        String time = dateValue.toString();
        return time.startsWith("000000")? "":time;
    }
}
